package entities.concept;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import option.KBVocabulary;

import utils.Display;

import entities.Individual;
import entities.KBEntity;
import entities.role.Role;

/**
 * Primitive/Atomic/Named Concepts
 * 
 * @author j55wu
 * 
 */
public final class PConcept extends AtomicConcept {
	private final String name;
	private static int freshcounter = 0;
	private static Map<String, PConcept> allGuards = new HashMap<String, PConcept>();
	private static Map<String, PConcept> allPCs = new HashMap<String, PConcept>();

	public static void resetCounterAndGuards() {
		freshcounter = 0;
		allGuards.clear();
		allPCs.clear();
	}

	private PConcept(String name) {
		this.name = name;
		allPCs.put(name, this);
	}

	public boolean isGuard() {
		return this.name.startsWith(KBVocabulary.GUARD);
	}

	public boolean isRoleGuard() {
		return this.name.startsWith(KBVocabulary.ROLE_GUARD);
	}
	
	public static PConcept getTopConcept() {
		return new PConcept(KBVocabulary.TOP);
	}

	public static PConcept getBottomConcept() {
		return new PConcept(KBVocabulary.BOTTOM);
	}

	public static PConcept getPConcept(String name) {
		if (name.equalsIgnoreCase(KBVocabulary.TOP)) {
			return KBVocabulary.CONCEPT_TOP;
		} else if (name.equalsIgnoreCase(KBVocabulary.BOTTOM)) {
			return KBVocabulary.CONCEPT_BOTTOM;
		}
		if (allPCs.containsKey(name)) {
			return allPCs.get(name);
		}
		return new PConcept(name);
	}

	public static int getNumFrenshConcept() {
		return freshcounter;
	}

	public static Map<String, PConcept> getGuardedConcept() {
		return allGuards;
	}

	public static PConcept newInternalPConcept() {
		return getPConcept(KBVocabulary.FRESH_CP + PConcept.freshcounter++);
	}
	
	//create an internal concept that depends on the given (complex) concept 
	public static PConcept newInternalPConcept(Concept dep) {
		freshcounter++;
		String ds = dep.toSerializedString();
		ds = ds.trim().replaceAll("\\s+", "_");
		return getPConcept(KBVocabulary.FRESH_CP +ds);
	}

	public static PConcept newGuardPConcept(Object o) {
		String name = "";
		if (o instanceof Role) {
			// for bpth features and roles
			name = KBVocabulary.ROLE_GUARD + ((Role) o).getRoleName();
		} else if (o instanceof Nominal || o instanceof Individual) {
//			name = KBVocabulary.NOMINAL_GUARD + ((Nominal) o).getName();
			return KBVocabulary.QUERY_GUARD;
		} 
//		else if (o instanceof Individual) {
//			name = KBVocabulary.NOMINAL_GUARD + ((Individual) o).getName();
//		} 
		else {
			System.err.println("Not supported guarded type: " + o.getClass());
		}
		if (allGuards.containsKey(name)) {
			return allGuards.get(name);
		}
		PConcept gc = getPConcept(name);
		allGuards.put(name, gc);
		return gc;
	}

	public int numberOfFreshPConceptCreated() {
		return freshcounter;
	}

	public boolean isTop() {
		return this.equals(KBVocabulary.CONCEPT_TOP);
	}

	public boolean isBottom() {
		return this.equals(KBVocabulary.CONCEPT_BOTTOM);
	}

	public String getPCName() {
		return this.name;
	}

	private volatile int hashCode = 0;

	@Override
	public int hashCode() {
		if (hashCode != 0) {
			return hashCode;
		}
		final int prime = 31;
		int result = 17;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		hashCode = result;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (!(obj instanceof PConcept))
			return false;
		if (getClass() != obj.getClass())
			return false;
		PConcept other = (PConcept) obj;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	@Override
	public String toString() {
		if (this.isTop()) {
			return Display.TOPUNICODE;
		} else if (this.isBot()) {
			return Display.BOTTOMUNICODE;
		} else {
			// String[] prefix ={
			// "http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#",
			// "http://www.Department0.University0.edu/"
			// };
			// for(String p:prefix){
			// if(name.contains(p)){
			// return name.replaceAll(p, "");
			// }
			// }
			return name;
		}
	}

	@Override
	public String toSerializedString() {
		if (this.isTop()) {
			return KBVocabulary.TOP;
		} else if (this.isBot()) {
			return KBVocabulary.BOTTOM;
		} else {
			return name;
		}
	}

	@Override
	public Concept getPrimeCopy() {
		if(this.isTop()){
			return this;
		}
		if(this.isBottom()){
			return this;
		}
		return new PConcept(this.name + Concept.PRIME);
	}
	
	@Override 
	public Set<KBEntity> extractSig(){
		Set<KBEntity> sig = new HashSet<KBEntity>();
		sig.add(this);
		return sig;
	}

}
